var DEFAULT_TOOLTIP_WIDTH = 300;
var DEFAULT_TOOLTIP_PADDING = 5;
var DEFAULT_CONTEXT_MENU_WIDTH = 100;
var STYLE_DEFAULT = 0;
var STYLE_HIGHLIGHT = 1;
var STYLE_HIDE = 2;

function SimpleTooltipTemplate() {
	this.width;		//width for tooltip table
	this.toHTML = function(title) {
		return "<DIV class=\"tooltip\"" + (this.width ? " style='width:" + this.width + "px;'" : "") + ">" + title + "</DIV>"
	}
}
/**
 *
 *	template for tooltip table.
 *  we use the toHTML() method to show the tooltip
 *  you can call the function as follows:
 *		var t = new TooltipTemplate(cap1, cap2, cap3, ...)
 * or
 *		var t = new TooltipTemplate(captionsArray)
 */
function TooltipTemplate(){
	this.captions;					//captions array
	this.width = DEFAULT_TOOLTIP_WIDTH;		//width for tooltip table
	this.padding = DEFAULT_TOOLTIP_PADDING;
	this.highlightedIndex = -1;
	this.remark;
	this.classes;
	this.hiddenIndices;

	if(arguments){
		if(arguments.length == 1 && arguments[0].constructor == Array){
			this.captions = arguments[0];
		}else{
			this.captions = new Array();
			for(var i = 0; i < arguments.length; i++){
				this.captions[i] = arguments[i];
			}
		}
	}

	if(!this.captions){
		this.captions = new Array();
	}

	this.addCaption = function(caption){
		if(caption){
			this.captions[this.captions.length] = caption;
		}
	};

	this.clone = function() {
		var tt = new TooltipTemplate(this.captions);
		tt.width = this.width;
		tt.highlightedIndex = this.highlightedIndex;
		tt.remark = this.remark;
		return tt;
	};

	this.highlight = function(index) {
		//this.highlightedIndex = index;
		return this.forClass(index, "highlight");
	};

	this.hide = function(index) {
		if(this.hiddenIndices == undefined) this.hiddenIndices = new Array();
		this.hiddenIndices[index] = true;
		return this;
	};

	this.forStyle = function(index, style) {
		switch(style) {
			case STYLE_HIGHLIGHT :
				return this.highlight(index);
				break;
			case STYLE_HIDE :
				return this.hide(index);
				break;
		}

		return this;
	};

	this.forClass = function(index, className) {
		if(this.classes == undefined) this.classes = new Array();
		this.classes[index] = className;
		return this;
	};

	//generate html for tooltip, taking column values array as argument
	//values must be corresponding to captions array (they should have the same length)
	this.toHTML = function(title, values){
		var _html = "<div class='tooltip'><table cellspacing='0' cellpadding='0' class='tooltip' style='width:" + this.width + "px;'>" +
						"<tr><td colspan=2 class='tooltip_title'>" + title + "</td></tr>";
		var even = true;
		for(var i = 0; i < this.captions.length; i++){
			if(this.hiddenIndices == undefined || this.hiddenIndices.length <= i || !this.hiddenIndices[i]) {
				var className = (this.classes == undefined || this.classes.length <= i ? null : this.classes[i]);
				var trClassName = (even ? "" : "class='tr_odd'");
				even = !even;
				_html += "<tr "+ trClassName +"><td nowrap='nowrap' class='" + (className ? className + " tooltip_caption" : "tooltip_caption") + "'>" + this.captions[i] + "</td><td class='" + (className ? className + " tooltip_text" : "tooltip_text") + "'>" + ((values && i < values.length) ? values[i] : "&nbsp;") + "</td></tr>";
			}
		}

		if(this.remark) {
			_html += "<tr><td class='remark' nowrap='nowrap' colspan='2'>" + this.remark + "</td></tr>";
		}

		_html += "</table></div>";
		return _html;
	};
}

/**
 *
 * function to show tooltip.
 * you can call the function as follows:
 *
 *		tooltip([tooltipTemplate], title, arg1, arg2, arg3)
 * or	
 *		tooltip([tooltipTemolate], title, argArray)
 *
 * taking an argument array of the column values 
 * the first argument is an optional TooltipTemplate,
 * if TooltipTemplate is absent, the function will use a default TooltipTemplate and 
 * use a window scope argument TOOLTIP_TITLE as tooltip title.
 */
function tooltip(){
	var tooltipTemplate;
	var title;
	var values;

	if(arguments && arguments.length == 1){
		title = arguments[0];
		tooltipTemplate = new SimpleTooltipTemplate();
	}
	else if(arguments && arguments.length >= 2){
		if(typeof arguments[0] == 'object'){
			if(arguments[0].constructor == TooltipTemplate) {
				tooltipTemplate = arguments[0];
				title = arguments[1];

				if((typeof arguments[2] == 'object') && arguments[2].constructor == Array){
					//value array?
					values = arguments[2];
				}else{
					values = new Array(arguments.length - 2);
					for(var i = 2; i < arguments.length; i++){
						values[i - 2] = arguments[i];
					}
				}
			} else if(arguments[0].constructor == SimpleTooltipTemplate) {
				tooltipTemplate = arguments[0];
				title = arguments[1];
			}
		}else{
			title = arguments[0];
			if((typeof arguments[1] == 'object') && arguments[1].constructor == Array){
				//value array?
				values = arguments[1];
			}else{
				values = new Array(arguments.length - 1);
				for(var i = 1; i < arguments.length; i++){
					values[i - 1] = arguments[i];
				}
			}
		}
	}

	if(!tooltipTemplate){
		tooltipTemplate = new TooltipTemplate();
	}

	//set width for overlib
	if(tooltipTemplate.width) ol_width = tooltipTemplate.width + (tooltipTemplate.padding ? 2 * tooltipTemplate.padding : 0);
	return tooltipTemplate.toHTML(title, values);
}

function ContextMenuTemplate() {
	this.menuItems;
	this.width = DEFAULT_CONTEXT_MENU_WIDTH;

	if(arguments){
		if(arguments.length == 1 && arguments[0].constructor == Array){
			this.menuItems = new Array();
			for(var i = 0; i < arguments[0].length; i++){
				this.addMenuItem(arguments[0][i]);
			}
		}else{
			this.menuItems = new Array();
			for(var i = 0; i < arguments.length; i++){
				this.addMenuItem(arguments[i]);
			}
		}
	}

	if(!this.menuItems){
		this.menuItems = new Array();
	}

	this.addMenuItem = function(text, target){
		if(text){
			this.menuItems[this.menuItems.length] = {label:text,target:target};
		}
	}

	this.clone = function() {
		var tt = new ContextMenuTemplate(this.menuItems);
		return tt;
	}

	//generate html for context menu, taking column hrefs array as argument
	//hrefs must be corresponding to captions array (they should have the same length)
	this.toHTML = function(hrefs){
		var _html = "<div class='tooltip'>";
		for(var i = 0; i < this.menuItems.length; i++){
			_html += "<div><a href='" + (hrefs.length > 0 && i < hrefs.length ? hrefs[i] : "") + "'";
			if(this.menuItems[i].target) _html += " target='" + this.menuItems[i].target + "'";
			_html += ">" + this.menuItems[i].label + "</a></div>" ;
		}
		_html += "</div>";
		return _html;
	}
}

var __ctx_menu_visible = false;
function ctxmenu() {
	var ctxMenuTemplate;
	var hrefs;

	if(arguments && arguments.length >= 2){
		if((typeof arguments[0] == 'object') && arguments[0].constructor == ContextMenuTemplate){
			ctxMenuTemplate = arguments[0];

			if((typeof arguments[1] == 'object') && arguments[1].constructor == Array){
				//hrefs array?
				hrefs = arguments[1];
			}else{
				hrefs = new Array(arguments.length - 1);
				for(var i = 1; i < arguments.length; i++){
					hrefs[i - 1] = arguments[i];
				}
			}
		}else{
			if((typeof arguments[1] == 'object') && arguments[1].constructor == Array){
				//hrefs array?
				hrefs = arguments[1];
			}else{
				hrefs = new Array(arguments.length - 1);
				for(var i = 1; i < arguments.length; i++){
					hrefs[i - 1] = arguments[i];
				}
			}
		}
	}

	if(!ctxMenuTemplate){
		ctxMenuTemplate = new ContextMenuTemplate();
	}

	//set width for overlib
	//ol_width = ctxMenuTemplate.width;
	__ctx_menu_visible = true;
	var olval = overlib(ctxMenuTemplate.toHTML(hrefs),WIDTH,ctxMenuTemplate.width,STICKY,MOUSEOFF,OFFSETX,0,OFFSETY,0);
	__tt_mouseout_handler = new Function("event", "__tt_mouseout(event)");
	addEvent(over, "mouseout", __tt_mouseout_handler, false);
	return olval;
}

function renderTooltipMap(chartMapRenderer, key, chartId, imgId, tooltipTemplateName, contextMenuTemplateName) {
	var imgdivId = imgId ? imgId : chartId;
	var imgdiv = (typeof(imgdivId) == "string" ? document.getElementById(imgdivId) : imgdivId);

	if(imgdiv) {
		var img;
		if(imgdiv.tagName.toUpperCase() == "IMG") {
			img = imgdiv;
			imgdiv = img.parentNode
		} else {
			img = imgdiv.getElementsByTagName("IMG")[0];
		}
		
		if(img) {
			var imgKeyStart = img.src.indexOf("img=") + 4;
			var imgKey = img.src.substring(imgKeyStart, img.src.indexOf("&", imgKeyStart));
			var rendererUrl = (chartMapRenderer ? chartMapRenderer : "chartMapRenderer");
			rendererUrl += (rendererUrl.indexOf("?") == -1 ? "?" : "&") + "key=" + key + "&chartId=" + chartId + "&imgKey=" + imgKey;
			if(tooltipTemplateName) {
				rendererUrl += "&tooltipTemplateName=" + tooltipTemplateName;
			}

			if(contextMenuTemplateName) {
				rendererUrl += "&contextMenuTemplateName=" + contextMenuTemplateName;
			}

			asyncRequest(rendererUrl, function(responseText) {
				var temp = document.createElement("DIV");
				setInnerHTML(temp, responseText);
				var mapName;
				for(var i = 0; i < temp.childNodes.length; i++) {
					if(temp.childNodes[i] && temp.childNodes[i].nodeType == 1 && temp.childNodes[i].nodeName.toUpperCase() == "MAP") {
						mapName = temp.childNodes[i].getAttribute("name");
						var existedMap = document.getElementById(mapName);
						if(existedMap) {
						//for(var existedMap = img.previousSibling; existedMap != null; existedMap = existedMap.previousSibling) {
						//	if(existedMap.nodeType == 1 && existedMap.nodeName.toUpperCase() == "MAP" && existedMap.getAttribute("name") == mapName) {
								//replace the map if a map of the image already exists
						//		img.useMap = null;
						//		existedMap.parentNode.removeChild(existedMap);
						//		break;
						//	}
						//}
							//replace the existed map
							setInnerHTML(existedMap, temp.childNodes[i].innerHTML);
						} else {
							imgdiv.insertBefore(temp.childNodes[i], img);
						}
						break;
					}
				}
				
				img.useMap = "#" + mapName;
			});

			return rendererUrl;
		} else {
			alert("Chart image not found: " + imgdivId);
		}
	} else {
		alert("Chart image not found: " + imgdivId);
	}
}

var __tt_mouseout_handler;

function nd2(evt) {
	if(__ctx_menu_visible) {
		//DON'T nd context menu!
		return true;
	}

	var e = evt || window.event;
	if(e && e.ctrlKey) {
		//hold tooltip
		//__tt_mouseout_handler = new Function("event", "__tt_mouseout(event)");
		//addEvent(over, "mouseout", __tt_mouseout_handler, false);
		
		return true;
	} else {
		return hideTooltip(e);
	}	
}

function __tt_mouseout(evt) {
	var e = evt || window.event;
	var toElement = e.toElement || e.relatedTarget;
	//hideTooltip if the cursor is out of the tooltip div
	if(!__isChildOf(over, toElement)) {
		hideTooltip(e);
		__ctx_menu_visible = false;
		if(__tt_mouseout_handler) {
			removeEvent(over, "mouseout", __tt_mouseout_handler, false);
			__tt_mouseout_handler = null;
		}
	}
}

function __isChildOf(pnode, cnode) {
	if(!pnode || !cnode || pnode.nodeType != 1 || pnode.childNodes.length == 0)
		return false;

	for(var i = 0; i < pnode.childNodes.length; i++) {
		if(pnode.childNodes[i] == cnode)
			return true;
		if(__isChildOf(pnode.childNodes[i], cnode))
			return true;
	}

	return false;
}

function hideTooltip(evt) {
	var e = evt || window.event;
	var ndVal = nd();
	if(e && e.button == 2) {
		document.oncontextmenu=__returnFalse;
		setTimeout("document.oncontextmenu=__returnTrue",100);
	}
	return ndVal;
}

function __returnFalse(){return false;}

function __returnTrue(){return true;}

function addEvent(obj, eventName, fn, useCapture) {   
	if(_isFirefox && eventName == "mousewheel") eventName = "DOMMouseScroll";
	if(obj.addEventListener) {   
		obj.addEventListener(eventName, fn, useCapture);
		return   true;
	} else if(obj.attachEvent) {   
		return obj.attachEvent("on" + eventName, fn);
	} else {
		obj["on" + eventName] = fn; 
	}
}

function removeEvent(obj, eventName, fn, useCapture) {
	if(_isFirefox && eventName == "mousewheel") eventName = "DOMMouseScroll";
	if(obj.removeEventListener) {   
		obj.removeEventListener(eventName, fn, useCapture);
		return   true;
	} else if(obj.detachEvent) {   
		return obj.detachEvent("on" + eventName, fn);
	} else {
		obj["on" + eventName] = null; 
	}
}

function __doc_onkeydown(evt) {
	var e = evt || window.event;
	if(e.keyCode == 17) {
		//capture CTRL key	
		o3_followmouse = ol_followmouse = 0;
		o3_allowmove = (o3_sticky || o3_followmouse==0) ? 0 : 1;
	}
}

function __doc_onkeyup(evt) {
	var e = evt || window.event;
	if(e.keyCode == 17) {
		//capture CTRL key
		o3_followmouse = ol_followmouse = 1;
		o3_allowmove = (o3_sticky || o3_followmouse==0) ? 0 : 1;
		hideTooltip();
	}
}

addEvent(document, "keydown", __doc_onkeydown, false);
addEvent(document, "keyup", __doc_onkeyup, false);

//default settings for overlib, refer to overlib.js
ol_hauto = 1;
ol_vauto = 1;